import type { WagmiConnectorInstance, WalletInstance } from '../types/Wallet'
import { type Config, type Connector, useConnect } from '@wagmi/vue'
import type { ConnectMutateAsync } from '@wagmi/vue/query'
import { addRecentWalletId, getRecentWalletIds } from './recentWalletIds'
import {
  connectorsWithRecentWallets,
  isEIP6963Connector,
  isRecentWallet,
  isWalletKitConnector,
  neutronKitConnectorWithWalletConnect
} from './groupedWallets'
import { indexBy } from '../utils/indexBy'
import { getDesktopDownloadUrl, getExtensionDownloadUrl, getMobileDownloadUrl } from '../wallets/downloadUrls'
import { inject } from 'vue'

export interface WalletConnector extends WalletInstance {
  ready?: boolean
  connect: () => ReturnType<ConnectMutateAsync<Config, unknown>>
  showWalletConnectModal?: () => Promise<void>
  recent: boolean
  mobileDownloadUrl?: string
  extensionDownloadUrl?: string
  desktopDownloadUrl?: string
  getDesktopUri?: () => Promise<string>
  getQrCodeUri?: () => Promise<string>
  getMobileUri?: () => Promise<string>
}

export function useWalletConnectors(mergeEIP6963WithWkConnectors = false): WalletConnector[] {
  const { connectAsync, connectors: defaultConnectors_untyped } = useConnect()
  const defaultCreatedConnectors = defaultConnectors_untyped as WagmiConnectorInstance[]

  const defaultConnectors = defaultCreatedConnectors.map((connector) => ({
    ...connector,
    /**
     * nkDetails 是可选的，它在 eip6963 连接器中不存在。当我们想在连接器中包含其他信息时，我们只在 'connectorsForWallets' 中注入 'wkDetails'。
     */
    ...(connector.nkDetails || {})
  })) as WalletInstance[]

  async function connectWallet(connector: Connector) {
    const result = await connectAsync({
      // todo 这个chainId暂时写死，后面优化
      // chainId: 1,
      // 这里的目标是确保用户在连接时始终位于受支持的链上。
      // 如果向 NeutronKitProvider 提供了 'initialChain' prop，请使用该属性。
      // intialChainId ??
      // 否则，如果钱包已经在支持的链上，请使用该链来避免链切换提示。
      // rainbowKitChains.find(({ id }) => id === walletChainId)?.id ??
      // 最后，回退到提供给 NeutronKitProvider 的第一个链。
      // rainbowKitChains[0]?.id,
      connector
    })

    if (result) {
      addRecentWalletId(connector.id)
    }

    return result
  }

  async function connectToWalletConnectModal(walletConnectModalConnector: Connector) {
    try {
      await connectWallet(walletConnectModalConnector)
    } catch (err) {
      const isUserRejection =
        // @ts-expect-error - Web3Modal v1 error name
        err.name === 'UserRejectedRequestError' ||
        // @ts-expect-error - Web3Modal v2 error message on desktop
        err.message === 'Connection request reset. Please try again.'

      if (!isUserRejection) {
        throw err
      }
    }
  }

  const getWalletConnectUri = async (connector: Connector, uriConverter: (uri: string) => string): Promise<string> => {
    const provider = await connector.getProvider()

    if (connector.id === 'coinbase') {
      // @ts-expect-error
      return provider.qrUrl
    }

    return new Promise<string>((resolve) =>
      // Wagmi v2 还没有 provider 的返回类型
      // @ts-expect-error
      provider.once('display_uri', (uri) => {
        resolve(uriConverter(uri))
      })
    )
  }

  const walletConnectModalConnector = defaultConnectors.find(
    (connector) => connector.id === 'walletConnect' && connector.isWalletConnectModalConnector
  )

  const eip6963Connectors = defaultConnectors.filter(isEIP6963Connector).map((connector) => {
    return {
      ...connector,
      groupIndex: 0
    }
  })

  const neutronKitConnectors = defaultConnectors
    .filter(isWalletKitConnector)
    .filter((wallet) => !wallet.isWalletConnectModalConnector)
    .filter((wallet) => {
      if (!mergeEIP6963WithWkConnectors) return true

      const existsInEIP6963Connectors = eip6963Connectors.some((eip6963) => eip6963.id === wallet.rdns)

      return !existsInEIP6963Connectors
    })
    .map((wallet) => neutronKitConnectorWithWalletConnect(wallet, walletConnectModalConnector!))

  const combinedConnectors = [...eip6963Connectors, ...neutronKitConnectors]

  const walletInstanceById = indexBy(combinedConnectors, (walletInstance) => walletInstance.id)

  // 最大的最近使用钱包的限制为3
  const MAX_RECENT_WALLETS = 3

  const recentWallets: WalletInstance[] = getRecentWalletIds()
    .map((walletId) => walletInstanceById[walletId])
    .filter(Boolean)
    .slice(0, MAX_RECENT_WALLETS)

  const walletConnectors: WalletConnector[] = []

  const combinedConnectorsWithRecentWallets = connectorsWithRecentWallets({
    wallets: combinedConnectors,
    recentWallets: recentWallets
  })

  for (const wallet of combinedConnectorsWithRecentWallets) {
    if (!wallet) continue

    const eip6963 = isEIP6963Connector(wallet)

    const recent = isRecentWallet(recentWallets, wallet.id)

    if (eip6963) {
      walletConnectors.push({
        ...wallet,
        iconUrl: wallet.icon!,
        ready: true,
        connect: () => connectWallet(wallet),
        groupName: 'Installed',
        recent
      })

      continue
    }

    walletConnectors.push({
      ...wallet,
      ready: wallet.installed ?? true,
      connect: () => connectWallet(wallet),
      desktopDownloadUrl: getDesktopDownloadUrl(wallet),
      extensionDownloadUrl: getExtensionDownloadUrl(wallet),
      groupName: wallet.groupName,
      mobileDownloadUrl: getMobileDownloadUrl(wallet),
      getQrCodeUri: wallet.qrCode?.getUri ? () => getWalletConnectUri(wallet, wallet.qrCode!.getUri!) : undefined,
      getDesktopUri: wallet.desktop?.getUri ? () => getWalletConnectUri(wallet, wallet.desktop!.getUri!) : undefined,
      getMobileUri: wallet.mobile?.getUri ? () => getWalletConnectUri(wallet, wallet.mobile!.getUri!) : undefined,
      recent,
      showWalletConnectModal: wallet.walletConnectModalConnector
        ? () => connectToWalletConnectModal(wallet.walletConnectModalConnector!)
        : undefined
    })
  }
  return walletConnectors
}
